package com.qd.panda.service.dc;

import cn.hutool.http.HttpUtil;
import com.cdqidi.config.mybatis.handler.GeoPoint;
import com.cdqidi.constant.ConstantDto;
import com.cdqidi.util.FileUtil;
import com.qd.common.panda.constant.PandaConstant;
import com.qd.common.panda.domain.entity.carpark.CarParkChargeTimeDTO;
import com.qd.common.panda.domain.entity.carpark.CarParkDTO;
import com.qd.common.sys.constant.Constants;
import com.qd.panda.dc.DcService;
import com.qd.panda.dc.dto.ChargeStationDTO;
import com.qd.panda.dc.dto.DcPage;
import com.qd.panda.model.*;
import com.qd.panda.service.park.*;
import com.qd.panda.service.stroke.BigDecimalUtil;
import com.qd.upload.config.UploadDTO;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.StringUtils;

import java.io.File;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 从数据中台获得充电站信息
 *
 * @author sjk
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class DcChargeStationService {
    private static final String END_TIME = "23:59:59";
    private static final String LOG_ERR = "截取时间异常,原始时间: {},st: {}";
    private final DcService dcService;
    private final CarParkService carParkService;
    private final CarParkLocationService carParkLocationService;
    private final CarParkImgService carParkImgService;
    private final CarParkTimeService carParkTimeService;
    private final CarParkChargeService carParkChargeService;
    private final CarParkChargeTimeService carParkChargeTimeService;
    private final ParkHolderService parkHolderService;

    private final UploadDTO uploadDto;


    @Transactional(rollbackFor = Exception.class)
    public void sync(Integer pageNo, Integer pageSize, LocalDateTime now) {
        List<ChargeStationDTO> list = new ArrayList<>();
        doSync(pageNo, pageSize, now, list);
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void afterCompletion(int status) {
                if(log.isDebugEnabled()) {
                    log.debug("同步充电站数据提交完成,status： {}", status);
                }
                if (TransactionSynchronization.STATUS_COMMITTED == status) {
                    list.forEach(chargeStation -> carParkService.updateToRedis(chargeStation.getParkId(), PandaConstant.FREE_STATUS_TENSION, chargeStation.getParkNums()));
                }
            }
        });

    }

    public void doSync(Integer pageNo, Integer pageSize, LocalDateTime now, List<ChargeStationDTO> list) {
        final DcPage<ChargeStationDTO> page = dcService.getChargeStationPage(pageNo, pageSize);
        final List<ChargeStationDTO> data = page.getData();
        if (null == data || data.isEmpty()) {
            return;
        }
        data.forEach(chargeStationDTO -> {
            //只处理parkId不为空的数据
            if (StringUtils.hasLength(chargeStationDTO.getParkId())) {
                saveOrUpdate(chargeStationDTO, now);
                list.add(chargeStationDTO);
            }
        });
        if (page.hasNext()) {
            doSync(page.getPageNo() + 1, page.getPageSize(), now, list);
        }

    }

    private void saveOrUpdate(ChargeStationDTO chargeStation, LocalDateTime now) {
        saveCarPark(chargeStation, now);
        saveCarParkLocation(chargeStation);
        saveCarParkImg(chargeStation);
        saveCarParkTime(chargeStation);
        saveCarParkCharge(chargeStation);
    }

    private void saveCarParkCharge(ChargeStationDTO chargeStation) {
        final CarParkCharge carParkCharge = Optional.ofNullable(carParkChargeService.getById(chargeStation.getParkId())).orElse(new CarParkCharge());
        carParkCharge.setPId(chargeStation.getParkId());
        carParkCharge.setStationId(chargeStation.getStationId());
        //下面的数字目前没有同步，只能默认为0
        carParkCharge.setFastChargeNum(0);
        carParkCharge.setFastChargeUse(0);
        carParkCharge.setSlowChargeNum(0);
        carParkCharge.setSlowChargeUse(0);
        //充电品牌
        carParkCharge.setChargeBrand(chargeStation.getType());
        //免费停车、24小时停车，这个也没有同步
        carParkCharge.setFreePark(ConstantDto.SF1);
        carParkCharge.setAllDay(ConstantDto.SF1);
        carParkChargeService.saveOrUpdate(carParkCharge);
        carParkChargeService.clearCache(carParkCharge);
        carParkCharge.freeData();

        //保存充电计费时段
        saveCarParkChargeTime(chargeStation);
    }


    private void saveCarParkChargeTime(ChargeStationDTO chargeStation) {
        //电费
        final String electricityFee = chargeStation.getElectricityFee();
        //服务费
        final String serviceFee = chargeStation.getServiceFee();
        if(log.isDebugEnabled()) {
            log.debug("electricityFee: {}", electricityFee);
            log.debug("serviceFee: {}", serviceFee);
        }

        Map<String, String> electricityMap = new LinkedHashMap<>();
        Map<String, String> serviceFeeMap = new LinkedHashMap<>();
        if (StringUtils.hasLength(electricityFee) && StringUtils.hasLength(serviceFee)) {
            parse(electricityFee.split(";"), electricityMap);
            parse(serviceFee.split(";"), serviceFeeMap);
        }
        final List<CarParkChargeTimeDTO> list = carParkChargeTimeService.getListByPId(chargeStation.getParkId());
        if (null != list && !list.isEmpty()) {
            for (CarParkChargeTimeDTO carParkChargeTimeDTO : list) {
                carParkChargeTimeService.removeById(carParkChargeTimeDTO.getTid());
            }
        }
        for (String key : electricityMap.keySet()) {
            final String s = serviceFeeMap.get(key);
            final String[] split = key.split("\\|");
            String startTime = split[0];
            String endTime = split[1];
            if (endTime.equals("24:00")) {
                endTime = END_TIME;
            }
            if (startTime.length() == 5) {
                startTime = startTime + ":00";
            }
            if (endTime.length() == 5) {
                endTime = endTime + ":00";
            }
            if (endTime.equals("24:00:00")) {
                endTime = END_TIME;
            }
            CarParkChargeTime carParkChargeTime = new CarParkChargeTime();
            carParkChargeTime.setPId(chargeStation.getParkId());
            carParkChargeTime.setStartTime(LocalTime.parse(startTime, DateTimeFormatter.ISO_TIME));
            carParkChargeTime.setEndTime(LocalTime.parse(endTime, DateTimeFormatter.ISO_TIME));
            final BigDecimal serviceCharge = BigDecimalUtil.buildDefaultScale(new BigDecimal(s), 4);
            final BigDecimal electricityFees = BigDecimalUtil.buildDefaultScale(new BigDecimal(electricityMap.get(key)), 4);
            carParkChargeTime.setServiceCharge(serviceCharge);
            carParkChargeTime.setElectricityFees(electricityFees);
            carParkChargeTime.setOriginalPrice(BigDecimalUtil.buildDefaultScale(serviceCharge.add(electricityFees), 4));
            carParkChargeTime.setConcessionalRate(carParkChargeTime.getOriginalPrice());
            carParkChargeTimeService.save(carParkChargeTime);
            carParkChargeTimeService.clearCache(carParkChargeTime);
            carParkChargeTime.freeData();
        }

    }

    /**
     * "electricityFee": "时间段:00:00-07:00,电费:0.7;时间段:07:00-11:00,电费:0.96;"
     * "serviceFee": "时间段:00:00-07:00,服务费:0.0;时间段:07:00-11:00,服务费:0.0;"
     * "electricityFee": "电费:00:00~07:00,0.3133;07:00~11:00,0.8416"
     * "serviceFee": "服务费:00:00~07:00,0.2500;07:00~11:00,0.1000;"
     */
    private static void parse(String[] array, Map<String, String> map) {
        for (String s : array) {
            final String[] split = s.split(",");
            if (split.length != 2) {
                return;
            }
            final String s1 = split[0];
            final String s2 = split[1];
            int st = s1.indexOf("-");
            if (st == -1) {
                st = s1.indexOf("~");
            }
            if (st == -1) {
                return;
            }
            String startTime = s1.substring(st - 5, st);
            String endTime = s1.substring(st + 1, st + 6);
            String s3;
            final String[] split1 = s2.split(":");
            if (split1.length == 1) {
                s3 = split1[0];
            } else {
                s3 = split1[1];
            }
            map.put(startTime + "|" + endTime, s3);
        }
    }

    private void saveCarParkTime(ChargeStationDTO chargeStation) {
        final String businessHours = chargeStation.getBusineHours();
        if(log.isDebugEnabled()) {
            log.debug("businessHours: {}", businessHours);
        }
        if (StringUtils.hasLength(businessHours)) {
            final int i = businessHours.indexOf("-");
            if (i == -1) {
                return;
            }
            int st = i - 5;
            if (st < 0) {
                log.error(LOG_ERR, businessHours, st);
                return;
            }
            final int length = businessHours.length();
            String startTime = businessHours.substring(st, i);

            st = i + 1;
            if (st > length) {
                log.error(LOG_ERR, businessHours, st);
                return;
            }
            int et = i + 6;
            if (et > length) {
                log.error(LOG_ERR, businessHours, st);
                return;
            }
            String endTime = businessHours.substring(st, et);
            if (startTime.length() == 5) {
                startTime = startTime + ":00";
            }
            if (endTime.length() == 5) {
                endTime = endTime + ":00";
            }
            if (endTime.equals("24:00:00")) {
                endTime = END_TIME;
            }
            CarParkTime carParkTime = Optional.ofNullable(carParkTimeService.getUniqueByPId(chargeStation.getParkId())).orElse(new CarParkTime());
            if (StringUtils.hasLength(carParkTime.getTId())) {
                carParkTimeService.removeById(carParkTime.getTId());
            }
            carParkTime.setPId(chargeStation.getParkId());
            carParkTime.setStartTime(LocalTime.parse(startTime, DateTimeFormatter.ISO_TIME));
            carParkTime.setEndTime(LocalTime.parse(endTime, DateTimeFormatter.ISO_TIME));
            carParkTimeService.save(carParkTime);
            carParkTimeService.clearCache(carParkTime);
            carParkTime.freeData();
        }

    }

    /**
     * [<a href="https://cdn-app.nio.com/PE/2021/10/28/62f02ed7-0142-4d2a-bbee-682596ebd99b_M.jpg">...</a>]
     */
    private void saveCarParkImg(ChargeStationDTO chargeStation) {
        String picture = chargeStation.getPictures();
        if(log.isDebugEnabled()) {
            log.debug("pictures: {}", picture);
        }
        if (picture.length() < 3) {
            return;
        }
        picture = picture.substring(2, picture.length() - 2);
        if(log.isDebugEnabled()) {
            log.debug("截取以后: {}", picture);
        }
        final String[] pictures = picture.split(",");

        final List<CarParkImg> list = carParkImgService.getListByPid(chargeStation.getParkId());
        if (null != list && !list.isEmpty()) {
            list.forEach(carParkImg -> carParkImgService.removeById(carParkImg.getId()));
        }
        int idx = 1;
        for (String p : pictures) {
            CarParkImg carParkImg = new CarParkImg();
            carParkImg.setPId(chargeStation.getParkId());
            carParkImg.setIdx(idx);
            buildImageUrl(carParkImg, p);
            idx++;
            carParkImgService.save(carParkImg);
            carParkImgService.clearCache(carParkImg);
            carParkImg.freeData();
        }
    }

    private void saveCarParkLocation(ChargeStationDTO chargeStation) {
        CarParkLocation carParkLocation = new CarParkLocation();
        carParkLocation.setPId(chargeStation.getParkId());
        carParkLocation.setLat(chargeStation.getStationLat());
        carParkLocation.setLng(chargeStation.getStationLng());
        carParkLocation.setAddress(chargeStation.getAddress());
        GeoPoint geoPoint = new GeoPoint();
        geoPoint.setLat(chargeStation.getStationLat());
        geoPoint.setLng(chargeStation.getStationLng());
        carParkLocation.setLocation(geoPoint);
        carParkLocation.setLocationType(5);
        carParkLocationService.saveOrUpdate(carParkLocation);
        carParkLocationService.clearCache(carParkLocation);
        carParkLocation.freeData();
    }

    private void saveCarPark(ChargeStationDTO chargeStation, LocalDateTime now) {
        boolean isAdd = true;
        CarPark carPark = carParkService.getById(chargeStation.getParkId());
        if (null == carPark) {
            carPark = new CarPark();
            carPark.setPId(chargeStation.getParkId());
            carPark.setIntoFreeTime(15);
            carPark.setPayFreeTime(15);
            carPark.setCarParkType(PandaConstant.CAR_PARK_TYPE_0);
            carPark.setAddTime(now);
            carPark.setThirdPartyBill(ConstantDto.SF1);
            carPark.setConfirmIn(ConstantDto.SF0);
            carPark.setConfirmOut(ConstantDto.SF0);
            carPark.setEnable(ConstantDto.SF1);
            carPark.setParkType(PandaConstant.PARK_TYPE_CHARGING_STATION);
            carPark.setOwnBusiness(ConstantDto.SF0);
            carPark.setOnStreet(ConstantDto.SF0);
            carPark.setParkSpaceType(PandaConstant.PARK_SPACE_TYPE2);
            carPark.setEtcPay(ConstantDto.SF1);
            final CarParkDTO carParkDTO = carParkService.modelToDto(carPark);
            parkHolderService.buildQrCode(carParkDTO);
            carPark.setCode(carParkDTO.getCode());
            carPark.setQrCode(carParkDTO.getQrCode());
        } else {
            carPark.setUpdateTime(now);
            isAdd = false;
        }
        carPark.setName(chargeStation.getStationName());
        carPark.setParkNum(null == chargeStation.getParkNums() ? 0 : chargeStation.getParkNums());
        carPark.setOperator(Constants.ADMIN_DEFAULT_ID);
        carPark.setOrgId(Constants.DEFAULT_TREE_PARENT_ID);
        if (isAdd) {
            carParkService.save(carPark);
        } else {
            carParkService.updateById(carPark);
        }
        carParkService.clearCache(carPark);
        carPark.freeData();
    }


    @SneakyThrows
    private void buildImageUrl(CarParkImg carParkImg, String url) {
        if(log.isDebugEnabled()) {
            log.debug("url: {}", url);
        }
        final String officialPath = uploadDto.getOfficialPath();
        File file = new File(officialPath + File.separator + "park");
        if (file.exists()) {
            final boolean b = file.mkdirs();
            if(log.isDebugEnabled()) {
                log.debug("文件夹: {},状态: {}" , file.getPath(), b);
            }
        }
        final String fileName = url.substring(url.lastIndexOf("/") + 1);
        final byte[] bytes = HttpUtil.downloadBytes(url);
        FileUtil.createFile(bytes, file.getPath(), fileName);
        carParkImg.setPicName(fileName);
        carParkImg.setPicPath("/park/" + fileName);
    }
}